package com.task.scheduler.persistence.entity;

import com.task.scheduler.enums.TaskStatus;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;

/**
 * 任务执行记录实体类，对应数据库表 task_executions
 */
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Entity
@Table(name = "task_executions", schema = "task_scheduler",
       indexes = {
           @Index(name = "idx_task_id", columnList = "task_id"),
           @Index(name = "idx_status", columnList = "status"),
           @Index(name = "idx_start_time", columnList = "start_time"),
           @Index(name = "idx_end_time", columnList = "end_time"),
           @Index(name = "idx_created_at", columnList = "created_at"),
           @Index(name = "idx_updated_at", columnList = "updated_at"),
           @Index(name = "idx_deleted", columnList = "deleted"),
           @Index(name = "idx_task_status_time", columnList = "task_id, status, start_time"),
           @Index(name = "idx_retry_count", columnList = "retry_count"),
           @Index(name = "idx_active_executions", columnList = "deleted, status, created_at")
       })
@EntityListeners(AuditingEntityListener.class)
public class TaskExecutionEntity {

    @Id
    @EqualsAndHashCode.Include
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, columnDefinition = "BIGINT AUTO_INCREMENT PRIMARY KEY")
    private Long id;

    @Column(name = "task_id", nullable = false, length = 36, columnDefinition = "VARCHAR(36) NOT NULL COMMENT '外键，关联tasks.id'")
    private String taskId;

    // 关联关系
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "task_id", referencedColumnName = "id", insertable = false, updatable = false,
                foreignKey = @ForeignKey(name = "fk_task_execution_task_id"))
    private TaskEntity task;

    @Column(name = "retry_count", nullable = false, columnDefinition = "INT DEFAULT 0 COMMENT '当前重试次数'")
    private int retryCount = 0;

    @Column(name = "start_time", columnDefinition = "DATETIME NULL COMMENT '执行开始时间'")
    private LocalDateTime startTime;

    @Column(name = "end_time", columnDefinition = "DATETIME NULL COMMENT '执行结束时间'")
    private LocalDateTime endTime;

    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false, columnDefinition = "ENUM('PENDING', 'PROCESSING', 'SUCCESS', 'FAILED', 'CANCELED') NOT NULL COMMENT '执行状态'")
    private TaskStatus status;

    @Column(name = "result", columnDefinition = "TEXT COMMENT '执行结果（JSON格式）'")
    private String result;

    @Column(name = "error_message", columnDefinition = "TEXT COMMENT '失败原因'")
    private String errorMessage;

    // 软删除标记
    @Column(name = "deleted", nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE COMMENT '软删除标记'")
    private Boolean deleted = false;

    // 版本控制（乐观锁）
    @Version
    @Column(name = "version", nullable = false, columnDefinition = "BIGINT DEFAULT 0 COMMENT '版本号（乐观锁）'")
    private Long version = 0L;

    // 审计字段
    @CreatedDate
    @Column(name = "created_at", updatable = false, columnDefinition = "DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间'")
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(name = "updated_at", columnDefinition = "DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间'")
    private LocalDateTime updatedAt;

    /**
     * 计算执行耗时（毫秒）
     */
    public Long getExecutionDurationMs() {
        if (startTime != null && endTime != null) {
            return java.time.Duration.between(startTime, endTime).toMillis();
        }
        return null;
    }

    /**
     * 判断是否执行成功
     */
    public boolean isSuccess() {
        return TaskStatus.SUCCESS.equals(status);
    }

    /**
     * 判断是否执行失败
     */
    public boolean isFailed() {
        return TaskStatus.FAILED.equals(status);
    }

    /**
     * 判断是否正在执行
     */
    public boolean isProcessing() {
        return TaskStatus.PROCESSING.equals(status);
    }

    /**
     * 判断是否待执行
     */
    public boolean isPending() {
        return TaskStatus.PENDING.equals(status);
    }

    /**
     * 判断是否已取消
     */
    public boolean isCanceled() {
        return TaskStatus.CANCELED.equals(status);
    }

    /**
     * 判断是否为最终状态（成功、失败、取消）
     */
    public boolean isFinalStatus() {
        return isSuccess() || isFailed() || isCanceled();
    }

    /**
     * 软删除执行记录
     */
    public void softDelete() {
        this.deleted = true;
    }

    /**
     * 恢复已删除的执行记录
     */
    public void restore() {
        this.deleted = false;
    }

    /**
     * 判断执行记录是否已删除
     */
    public boolean isDeleted() {
        return Boolean.TRUE.equals(deleted);
    }

    /**
     * 开始执行
     */
    public void startExecution() {
        this.status = TaskStatus.PROCESSING;
        this.startTime = LocalDateTime.now();
    }

    /**
     * 执行成功
     */
    public void markSuccess(String result) {
        this.status = TaskStatus.SUCCESS;
        this.endTime = LocalDateTime.now();
        this.result = result;
        this.errorMessage = null;
    }

    /**
     * 执行失败
     */
    public void markFailed(String errorMessage) {
        this.status = TaskStatus.FAILED;
        this.endTime = LocalDateTime.now();
        this.errorMessage = errorMessage;
    }

    /**
     * 取消执行
     */
    public void markCanceled(String reason) {
        this.status = TaskStatus.CANCELED;
        this.endTime = LocalDateTime.now();
        this.errorMessage = reason;
    }

    /**
     * 增加重试次数
     */
    public void incrementRetryCount() {
        this.retryCount++;
    }

    /**
     * 判断是否可以重试
     */
    public boolean canRetry(int maxRetry) {
        return this.retryCount < maxRetry && (isFailed() || isPending());
    }
}
